<?php

namespace Library\Auth;

class OpenIDAuth extends \Library\Auth {

	const STORE_PATH = '/tmp/openluke_store';

	private $_auth;
	private $_user;
	private $_openid;
	
	public function __construct( $auth = array() ) {
		parent::__construct();
		$this->_auth = $auth;
	}
	
	public function getUser() {
		if( $this->_user === null ) {
			if( isset( $this->_auth['user_id'] ) ) {
				$this->_user = \Bean\User::get( $this->_auth['user_id'] );
			}
		}
		return $this->_user;
	}
	
	public function getOpenid() {
		return $this->_openid;
	}
	
	public function getOpenidId() {
		return $this->_auth['openid_id'];
	}
	
	public function check( $data ) {
		$this->_openid = $data['openid'];
		
		$action = new \Action\User\CheckOpenID( $data );
		$result = $action->execute();
		if( !$result['valid'] ) {
			throw new \Exception( $result['message'] );
		}
	}
	
	public function create( $data ) {
		_q()->set1( 'auth_openids', array(
			'user_id' => $data['user_id'],
			'openid' => $data['openid']
		) );
	}
	
	public function authenticate( $data ) {
		$this->_openid = $data['openid'];

		$store = new OpenIDAuth\OpenID\FileStore( self::STORE_PATH );
		$consumer = new OpenIDAuth\OpenID\Consumer( $store );

		if( !$_POST ) {
			return $this->_getResult( $consumer );
		}
		else {
			$this->_sendRequest( $consumer );
		}
		return null;
	}

	public function change( $data ) {
		_c( 'OpenID', $data['new_openid'] );
		
		$user = $this->authenticate( $data );

		_q()->upt( 'auth_openids', 
			array( 'openid' => $this->_openid ),
			array( 'openid_id' => $this->getOpenidId() ) );
	}
	
	private function _getResult( $consumer ) {

		$query = OpenIDAuth\OpenID::getQuery();
		unset( $query['action'] );
		$response = $consumer->complete( $this->_getReturnTo2(), $query );

		switch( $response->status ) {
			case Auth_OpenID_CANCEL:
				throw new \Exception( 'Verification cancelled' );
				break;
			case Auth_OpenID_FAILURE:
			print_r( $response );
				throw new \Exception( 'OpenID authentication failure' );
				break;
			case Auth_OpenID_SUCCESS:
				$openid = _q()->get1( 'auth_openids', array( 'openid' => $this->_openid ) );
				return \Bean\User::get( $openid['user_id'] );
				break;
			default:
				throw new \Exception( 'Unknown openid response status' );
		}
	}
	
	private function _sendRequest( $consumer ) {
		
		$auth_request = $consumer->begin( $this->_openid );
		
		if( $auth_request->shouldSendRedirect() ) {
		
			$redirect_url = $auth_request->redirectURL( $this->_getTrustRoot(), $this->_getReturnTo() );

			if( OpenIDAuth\OpenID::isFailure( $redirect_url ) ) {
				throw new \Exception( 'Could not redirect to server: ' . $redirect_url->message );
			} else {
				header( 'Location: ' . $redirect_url );
				exit(0);
			}
			
		} else {

			$form_id = 'openid_message';
			$form_html = $auth_request->htmlMarkup(
				$this->_getTrustRoot(), $this->_getReturnTo(),
				false, array('id' => $form_id));

			if( OpenIDAuth\OpenID::isFailure( $form_html ) ) {
				throw \Exception( 'Could not redirect to server: ' . $form_html->message );
			}
			else {
				print $form_html;
				exit(0);
			}
		}
	}
	
	private function _getTrustRoot() {
		return sprintf("%s://%s:%s%s/",
			$this->_getScheme(), $_SERVER['SERVER_NAME'],
			$_SERVER['SERVER_PORT'],
			dirname($_SERVER['REQUEST_URI']));
	}
	
	private function _getReturnTo() {
		return sprintf("%s://%s:%s%s",
			$this->_getScheme(), $_SERVER['SERVER_NAME'],
			$_SERVER['SERVER_PORT'],
			dirname($_SERVER['REQUEST_URI']) . '/' . $_GET['action'] . '?sent=true&Action_Authenticate=true&auth[1][kind]=OpenID&auth[1][openid]=' . urlencode($this->_openid));
	}
	
	private function _getReturnTo2() {
		return sprintf("%s://%s:%s%s",
			$this->_getScheme(), $_SERVER['SERVER_NAME'],
			$_SERVER['SERVER_PORT'],
			dirname($_SERVER['REQUEST_URI']) . '/' . $_GET['action'] );
	}
	
	private function _getScheme() {
		$scheme = 'http';
		if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') {
			$scheme .= 's';
		}
		return $scheme;
	}
}
